﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Data.Schema.Package.Project;
using Microsoft.Data.Schema.Sql.SchemaModel;
using Microsoft.Data.Schema.SchemaModel;
using Microsoft.VisualStudio.Data.Schema.Package.Project.Internal;
using TFDP.VsPackage.Support;
using System.Linq;
using TFDP.Common;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Data.Schema.Package.Internal;
using System.ComponentModel.Composition;
using System.IO;

namespace TFDP.VsPackage.Extenders
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class ExtendedType : DatabaseProjectNodeExtender, ICustomTypeDescriptor
    {
        public ExtendedType(IDatabaseNode node, EnvDTE.IExtenderSite extenderSite, int cookie)
            : base(node, extenderSite, cookie)
        {
        }

        public ExtendedType(IDatabaseNode node, EnvDTE.IExtenderSite extenderSite, int cookie, IExtenderType additionalProperties)
            : base(node, extenderSite, cookie)
        {
            this.AdditionalProperties = additionalProperties;

            if(this.AdditionalProperties != null)
                this.AdditionalProperties.Node = node;
        }

        #region Default Properties
        public const string IsGeneratedProperty = "IsGenerated";
        [DisplayName("Auto generated")]
        [Description("true if this object is auto generated")]
        [Category("T4 Generator Extensions")]
        [DefaultValue(false)]
        [ReadOnly(true)]
        public bool IsGenerated
        {
            get
            {
                string tmp = GetPropertyValue(IsGeneratedProperty);

                bool retval = false;

                Boolean.TryParse(tmp, out retval);

                return retval;
            }
            set
            {
                SetPropertyValue(IsGeneratedProperty, value.ToString());
            }
        }

        public const string SkipAutogenerationProperty = "SkipAutogeneration";
        [DisplayName("Skip autogeneration")]
        [Description("true if this template should not be transformed on save")]
        [Category("T4 Generator Extensions")]
        [DefaultValue(false)]
        [ReadOnly(false)]
        public bool SkipAutogeneration
        {
            get
            {
                string tmp = GetPropertyValue(SkipAutogenerationProperty);

                bool retval = false;

                Boolean.TryParse(tmp, out retval);

                return retval;
            }
            set
            {
                SetPropertyValue(SkipAutogenerationProperty, value.ToString());
            }
        }
        #endregion

        #region Property Plumbing
        protected string GetPropertyValue(string propertyName)
        {
            string returnValue = String.Empty;

            this.Node.GetItemAttribute(propertyName, out returnValue);

            return returnValue;
        }

        protected void SetPropertyValue(string propertyName, string value)
        {
            this.Node.SetItemAttribute(propertyName, value);
        } 
        #endregion

        #region Additional Properties
        [Browsable(false)]
        [ComVisible(false)]
        private IExtenderType AdditionalProperties
        {
            get;
            set;
        }
        #endregion

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            PropertyDescriptorCollection standard = TypeDescriptor.GetProperties(this, attributes, true);

            PropertyDescriptorCollection additional = null;

            bool isTemplate = (Path.GetExtension(this.Node.Url).ToLower() == ".tt");

            if (!this.IsGenerated && !isTemplate)
            {
                if (AdditionalProperties != null)
                    additional = TypeDescriptor.GetProperties(AdditionalProperties, attributes, true);
            }

            List<PropertyDescriptor> properties = new List<PropertyDescriptor>();

            foreach (PropertyDescriptor pd in standard)
            {
                if (!isTemplate && pd.Name == SkipAutogenerationProperty)
                    continue;

                properties.Add(pd);
            }

            if(additional != null)
                foreach (PropertyDescriptor pd in additional)
                    properties.Add(pd);

            return new PropertyDescriptorCollection(properties.ToArray(), true);
        }

        public PropertyDescriptorCollection GetProperties()
        {
            return GetProperties(null);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            if (pd.ComponentType != typeof(ExtendedType))
                return AdditionalProperties;
            else
                return this;
        }

        #endregion
    }
}
